Skip to content

Conversation

naddison36
Copy link
Collaborator

@naddison36 naddison36 commented Jun 30, 2025

A new staking strategy that uses merkle proofs to verify the operations of validators running on the beacon chain.

Objectives

  • Consolidation of validators to reduce the operation costs.
  • Consolidation to a single staking strategy to reduce the Vault gas costs.
  • Better protection against front-running of deposits to a new validator.
  • On-chain withdrawals reduces the dependency on third party node operators managing validator private keys.
  • Merkle proofs of the beacon chain is much more secure than Oracles providing validator balances.

Links

Relevant Pectra Release changes

  • EIP-6110 On-Chain Validator Deposits
  • EIP-7002 Execution layer triggerable withdrawals
  • EIP-7251 Increase the MAX_EFFECTIVE_BALANCE
  • EIP-7685 General purpose execution layer requests

Contracts

The scope of the contracts of this build is

  • CompoundingStakingSSVStrategy is the new staking contract.
  • CompoundingValidatorManager is inherited by CompoundingStakingSSVStrategy
  • CompoundingStakingStrategyView has two view functions for CompoundingStakingSSVStrategy
  • BeaconProofs called from CompoundingValidatorManager

The following libraries have also be built

  • BeaconRoots
  • BeaconProofsLib
  • PartialWithdrawal
  • Merkle
  • Endian
oethContracts oethContracts

Hoodi

Contract Name Address
CompoundingStakingSSVStrategyProxy 0xb5B92DEFC0a9623E31e10Fe0BaE02610bf76fd09
CompoundingStakingStrategyView 0x13eDDe0650E41f3B54E43f6783EA6eFD49F0C804
BeaconProofs 0x2E6854F44b9bF035ca53ec121A78621729B537ff
OETHVaultProxy 0xD0cC28bc8F4666286F3211e465ecF1fe5c72AC8B
OETHProxy 0xbebDca6eF7452953e0AB5cebE2A174B71208B13a
NativeStakingSSVStrategyProxy 0x95DdB082cf2b8Bb4a4A358A8817a848cE32e446b
NativeStakingFeeAccumulatorProxy 0x27281CE00322Ee8b7C078788Fb624D051F5F7689

States

stakingValueTransitions stakingValidatorStates stakingStates

Beacon chain data

BeaconBlock
├── slot: Slot
├── proposer_index: ValidatorIndex
├── parent_root: Root
├── state_root: Root  # Merkle root of BeaconState
│   └── BeaconState  # Does not include all fields
│       ├── validators: List[Validator, MAX_VALIDATORS]
│       │   ├── pubkey: BLSPubkey
│       │   ├── withdrawal_credentials: Bytes32
│       │   ├── effective_balance: uint64
│       │   ├── slashed: boolean
│       │   ├── activation_epoch: Epoch
│       │   ├── exit_epoch: Epoch
│       │   └── withdrawable_epoch: Epoch
│       ├── balances: List[Gwei, MAX_VALIDATORS]
│       ├── eth1_data: Eth1Data
│       │   ├── deposit_root: Root
│       │   ├── deposit_count: uint64
│       │   └── block_hash: Hash32
│       ├── eth1_deposit_index: uint64
│       └── deposit_requests_start_index: uint64
│       └── deposit_balance_to_consume: Gwei
│       └── pending_deposits: List[PendingDeposit, PENDING_DEPOSITS_LIMIT]
└── body_root: Root
    └── BeaconBlockBody  # Does not include all fields
        ├── eth1_data: Eth1Data
        ├── attestations: List[Attestation, MAX_ATTESTATIONS]
        ├── slashings: List[Slashing, MAX_SLASHINGS]
        ├── sync_aggregate: SyncAggregate
        ├── deposits: List[Deposit, MAX_DEPOSITS]
        ├── execution_payload: Root # at index 9
        │   └── ExecutionPayload
        │       ├── block_number: uint64  # at index 6
        └── requests: List[Request, MAX_REQUESTS]
            ├── type: uint8 (deposit, exit, consolidation)
            ├── data: Bytes (e.g., DepositData, ExitData)
            └── source: Hash32 (EL block hash)

Beacon Container Specs

To get the consolidate beacon chain specification for the last Pectra release

git clone https://github.com/ethereum/consensus-specs.git
cd consensus-specs
make pyspec

build/lib/eth2spec/electra/mainnet.py will have the full, consolidated changes. This includes all the beacon chain container definitions. eg BeaconBlock, BeaconBlockBody, BeaconState, Validator...

Processes

Register a SSV validator

oethProcesses-register

Initial deposit to a new validator

oethProcesses-deposit-new

Deposit more to existing validator

oethProcesses-deposit-existing

Verify validator

oethProcesses-verify-validator

Verify deposit to validator

oethProcesses-verify-deposit

Update strategy balances

oethProcesses-verify-balances

Withdrawals

oethProcesses-withdraw

Admin

oethProcesses-admin

Build

Keeping the contract under 24Kb has been a problem during development. The following will show the contract size of the compile contracts including CompoundingStakingSSVStrategy.

export CONTRACT_SIZE=true
npx hardhat compile

Testing

Unit Tests

Are main strategy unit tests in contracts/test/strategies/compoundingSSVStaking.js

There are also unit tests of the beacon merkle proofs in contracts/test/beacon/beaconProofs.js

yarn test

Fork Tests

There are no fork tests of the strategy as its hard to mock the beacon chain. But there are fork tests of various beacon chain contracts and libraries. These includes:

  • contracts/test/beacon/beaconConsolidation.mainnet.fork-test.js
  • contracts/test/beacon/beaconProofs.mainnet.fork-test.js
  • contracts/test/beacon/beaconRoots.mainnet.fork-test.js
  • contracts/test/beacon/partialWithdrawal.mainnet.fork-test.js

Hoodi Testnet

Hoodi faucet: https://hoodi-faucet.pk910.de/
SSV faucet: https://faucet.ssv.network/

Contracts have been deployed to Hoodi with deployment scripts in contracts/deploy/hoodi

 export DEPLOYER_PK=
yarn run deploy:hoodi
npx hardhat etherscan-verify --network hoodi --api-url https://api-hoodi.etherscan.io

Hoodi testing using Hardhat tasks

# Set `DEFENDER_API_KEY` and `DEFENDER_API_SECRET` in your `.env` file for the Hoodi Defender Relayer

# Get some WETH
npx hardhat depositWETH --amount 64 --network hoodi

# Mint OETH with approval
npx hardhat mint --asset WETH --amount 64 --symbol OETH --network hoodi

# Deposit old to native staking strategy
npx hardhat depositToStrategy --symbol OETH --strategy NativeStakingSSVStrategyProxy --assets WETH --amounts 64 --network hoodi

# Check the WETH was deposited
npx hardhat snapStaking --network hoodi

# Set the amount of Ether than can be staked before needing a reset
npx hardhat setStakeETHThreshold --amount 500 --network hoodi
# Reset the stakeETHTally if needed
npx hardhat resetStakeETHTally --network hoodi

# Register an old sweeping validator
npx hardhat registerValidators --days 30 --validators 1 --network hoodi

# stake to the old sweeping validator
npx hardhat stakeValidators --network hoodi

# Check the validator is active
npx hardhat snapStaking --network hoodi

# Deposit to new compounding staking strategy
npx hardhat depositToStrategy --symbol OETH --strategy CompoundingStakingSSVStrategyProxy --assets WETH --amounts 64 --network hoodi

# Check WETH in the new strategy
npx hardhat snapStakingStrat --network hoodi

# Request a new SSV validator via the staking contract
# Must include some SSV for the first validator
npx hardhat registerValidator --operatorids 345,346,347,348 --pubkey 0x8ac167403e9e81ceb3f612aed30c0d0667c1dfd6b716802798e9ea20b5fae153fd3b7be2676b239f4b7efaf0b2d6b12c --shares 0xa946648c8a243cd45d3fa5ea0d06fde42cba42985eaed0a4487ed669e3d7e5c710a9c3a951150694599380cde0314992074d615b0227ce5d4fed279f965e29a506e946070d7327879d8545154bba07ca1267452bc525ec0caaf6018122dd14398eb6a048186f2244fb6e40e6f568879175f63fcf86d3026f71f4bf0291badd08ea846b673b9d1cd2930bfadf6c719f84adf51764730105fb99d69b481f16cf3c377d6affe638587a65683868db173749d1c0ba127ac91fe185b5e0798909358cb838eb8659c08f9a07e53b0d354ece6408e1c145d9566b31afc8dee9b602dc10a26d252913b86f445b85dfc09ec94489ae21807065e5183b63dd78530d7295f24273af6c453c8e1d0ba5e9713c486326a5a735caee43d465d49df35a353177751c1a2a72768051a9ab8309c2a620dbbba3e6aa4a73366c480256092218345aab153516acbdbbd4566490518e011be8fc1607f4eaa9c8f8c9bd322bc738f30c5bc546516ed5e3d94224b51653919824057ba2c83547fb79afc1d451d36a066120d351b270266369c7108e81134663c6fcc5f319ca7043e42c42d93b4fbae294e169fd2d8109041fa99a762a307193fffd14f87c3191a6b86239885b46ad240cedd7ae6788aa209ee5b18357d397cb8cdd86d3395f6f8907870c5f743dc24448a2a2652b1cc4ace8278cbc084a433de451a414342c0c1150f37cab8fd3cf817137b5fa99ebae7e8fc33e3316670ee4d0c7ebdb8aa25c3677978654615093f8b95a91abb1b15d675c23c52dffbf6b1eddd82f5d44040f9b19c25c76d11efda396c2c82b9982aa42b309a7f94e3445c015f596e8673bcf8c56b423cb132910ee4a2158f18287e9bc3d1e1ad856f9f576b869a11ecf51b337db8b260d79b8cbfa68ccb056de2e49d77d2826eab59f4b0a56e90f939024e878a3c4e70492df9ec3c61ae0b94d8e606e92ebf4444fca8dd745b0053f9b2657e81c9631f215854d4679d612631f7941aba03fdd068d5a43225c65dbab617a7b2736756394d119909397c0d0663c193a1cab280b1990dc3ce4d805fc2e5a66dca2523e27300894c6a6d67015e25b7406fee582b83ca6afa106185f0e680c53801df1bab343917c75c3106908a0730a3d3f7567c6dda09228d5d6bd6d1bdd6afc4ab6c311f2cb698bbdd43713e254ecbd64a65ca3c44b0f2428ec9bd23d045038ae1a52f3a1c98076281cbeaf5076807c57df72703394e8c4e33e1a51fb5e740176902e38033e9d718f12db9897f82b1826f541e970ec159c92a847b1ebc2b5ea9052a6a3c4f42f2f43723194ad549b0583972703ec4443e6513076c87c8758fd714bd629d45f2eba57d834c8569fb02a701b2db3a3bfeae0e5314a2f05e1d2d8c2909af9b468f25c278acbed3b6a9a8e7bea7fb9195115f0add6179717b4054230ef78c80fa3acfc54a2bd9d1eb4b9bf932755042617fd53725aefd8e3aa0d1d6ec508a8754181497af2b753884e8952df0197a25ab5d785e4ea3979fdfedcccc9e89117975ee9a055930868fde4215535c8582639310c8b0c06b9892406d7e4ddf8c899e662fbac44d232888d5cb7ca19f3e48d098f12fbf1082d3452e606c65af26e9a68a36d4921113c14724325a3fcd0382ee5c73309fd9b92752dc89fff2691926dc0a403ee26dbb19edbc79df12f9efad2b0778eccd680cebf91392c6e8b338e1148d691efae07c5a6702a6297d3fc5bfacf5214829c352b77c627c8602d1a82a61440db4661ca9132618846304e1883fc37e08f7bea99aaea7bbbf2193ec1d113c51571bbe9771eebda5a58ca9b25b7419d794eb147ea52ba250cb9344b27a31eeec851a74547d6 --network hoodi

# Deposit to a new validator
# Must include the sig and deposit-message-root for the first deposit
npx hardhat stakeValidator --pubkey 0x8ac167403e9e81ceb3f612aed30c0d0667c1dfd6b716802798e9ea20b5fae153fd3b7be2676b239f4b7efaf0b2d6b12c --sig 0xb276484b5e40626330572d6f2f29905afec33b84e8d1fb15d16f39a5765ea7467402b4f42f1deef4e18d88de662326270e32010e731f527eea0d02f0e0cec91bcb5dc34b4ec9b509703844c3ffb71cea608886386dc4a11f166cee5a5a9d0bb8 --deposit-message-root 0x2fd84757b8e1da3914a415b513e35386da75eab463c2aef1b74cd19987cf8806 --amount 1 --network hoodi

# Verify the validator
# make sure BEACON_PROVIDER_URL is pointing to the Hoodi beacon chain
npx hardhat verifyValidator --index 1222774 --network hoodi
npx hardhat getValidator --index 1222774 --network hoodi

# Verify the deposit
npx hardhat verifyDeposit --root 0x778706f09de3313d13e6bb7a1a0d177fae657119da51c70ed185f8fdde1cb34b --network hoodi

# Snap the ETH balance
npx hardhat snapBalances --network hoodi

# Verify the balances
npx hardhat verifyBalances --network hoodi

# Partial withdrawal from a validator
npx hardhat withdrawValidator --amount 5 --pubkey 0x8f4429ea2bd4228f0ca74b4e232b03f6e0ef5bd2420951240dfe2acc423944aab40530b5f3165f231600e1a90fed3d4e --network hoodi

# Exit from a validator with a zero amount
npx hardhat withdrawValidator --amount 0 --pubkey 0x8ac167403e9e81ceb3f612aed30c0d0667c1dfd6b716802798e9ea20b5fae153fd3b7be2676b239f4b7efaf0b2d6b12c --network hoodi

Deployment

Hoodi

 export DEPLOYER_PK=
yarn run deploy:hoodi

npx hardhat etherscan-verify --contract-name CompoundingStakingSSVStrategy --network hoodi --api-url https://api-hoodi.etherscan.io
npx hardhat etherscan-verify --contract-name BeaconProofs --network hoodi --api-url https://api-hoodi.etherscan.io

npx hardhat tenderlyUpload --name CompoundingStakingSSVStrategy --network hoodi
npx hardhat tenderlyUpload --name BeaconProofs --network hoodi

Code Change Checklist

To be completed before internal review begins:

  • The contract code is complete
  • Executable deployment file
  • Fork tests that test after the deployment file runs
  • Unit tests *if needed
  • The owner has done a full checklist review of the code + tests

Internal review:

  • Two approvals by internal reviewers

Copy link

github-actions bot commented Jun 30, 2025

Warnings
⚠️ 👀 This PR needs at least 2 reviewers

Generated by 🚫 dangerJS against 4e1a4fb

Copy link

codecov bot commented Jun 30, 2025

Codecov Report

❌ Patch coverage is 99.03148% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 40.07%. Comparing base (6c5c3a1) to head (0b7bca8).

Files with missing lines Patch % Lines
...gies/NativeStaking/CompoundingValidatorManager.sol 98.62% 3 Missing ⚠️
...es/NativeStaking/CompoundingStakingSSVStrategy.sol 98.03% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2559      +/-   ##
==========================================
+ Coverage   35.37%   40.07%   +4.69%     
==========================================
  Files         112      122      +10     
  Lines        5331     5744     +413     
  Branches     1412     1526     +114     
==========================================
+ Hits         1886     2302     +416     
+ Misses       3444     3440       -4     
- Partials        1        2       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

naddison36 and others added 30 commits September 17, 2025 09:48
* Allow a validator full exit when it is already exiting

* Updated validator state diagram
* Restricted the pending deposit index to uint32 as the pending deposits container height is only 28

* Added check that pendingDepositIndex is < 2**27 in verifyPendingDeposit
…sit queue is empty (#2669)

* Can verify a deposit if the validator is exiting and the pending deposit queue is empty

* add comment

---------

Co-authored-by: Domen Grabec <[email protected]>
…#2673)

* Allow verification of a non 0x02 validator so it can be marked as INVALID

* Added unit test for verifying an invalid validator type

* pass withdrawal credentials when verifying validator (#2674)

* Fixed verifyValidator Hardhat task

* Fixed beacon proof fork test

---------

Co-authored-by: Domen Grabec <[email protected]>
* Allow withdraws from the staking strategy by the Registrator for automation

* Added signMessage HH task for Etherscan ownership verification

* Deployed latest strategy contract to Hoodi

* Added autoValidatorWithdrawals Hardhat task

* Fixed unit tests

* Changed execute option to dryrun

* Created reusable totalPartialWithdrawals function
Fixed summing of partial withdrawal amount as its in Gwei
* Revert upgrading the old native staking strategies

* Restored old Hardhat tasks to bulk exit and remove validators from the old native staking strategies
* Added autoValidatorDeposits Hardhat task

* Set the new staking strategy as the default for the OETH Vault

* Refactor auto deposit
* Fix auto deposits to include pending deposits

* Increased MAX_DEPOSITS from 12 to 32
Deployed latest strategy contract to Hoodi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants